<template>
  <div>
    <n-card :bordered="false" class="mt-4 proCard">
      <BasicTable
        :columns="columns"
        :request="loadDataTable"
        :row-key="(row) => row.id"
        ref="actionRef"
        :actionColumn="actionColumn"
        :pagination="false"
      >
        <template #tableTitle>
          <n-button type="primary" @click="() => {
            modelDetails.type = 0;
            modelDetails.show = true;
            modelDetails.formData = {
              roleName: '',
              roleKey: '',
              sort: 1,
              menuIds: []
            }
          }">添加角色</n-button>
        </template>
      </BasicTable>
    </n-card>

    <n-modal
      v-model:show="modelDetails.show"
      preset="card"
      style="width: 550px"
      :title="modelDetails.title[modelDetails.type]"
      size="huge"
    >
      <n-form
        :model="modelDetails.formData"
        :rules="rules"
        ref="formRef"
        label-placement="left"
        :label-width="100"
        class="py-4"
      >
        <n-form-item label="角色名称" path="roleName">
          <n-input placeholder="请输入菜单名称" v-model:value="modelDetails.formData.roleName" />
        </n-form-item>
        <n-form-item label="角色键" path="roleKey">
          <n-input placeholder="请输入菜单键" v-model:value="modelDetails.formData.roleKey" />
        </n-form-item>
        <n-form-item label="绑定菜单" path="menuIds">
          <n-tree
            block-line
            cascade
            checkable
            key-field="id"
            label-field="menuName"
            :virtual-scroll="true"
            :data="treeData"
            :expandedKeys="expandedKeys"
            :checkedKeys="modelDetails.formData.menuIds"
            style="max-height: 650px; overflow: hidden"
            @update:expanded-keys="onExpandedKeys"
            @update:checked-keys="onCheckedKeys"
          />
        </n-form-item>
        <n-form-item label="排序" path="sort">
          <n-input-number
            v-model:value="modelDetails.formData.sort"
            placeholder="角色序号"
            :min="1"
          />
        </n-form-item>
        <n-form-item path="auth" style="margin-left: 100px">
          <n-button type="primary" :loading="subLoading" @click="formSubmit">
            {{ modelDetails.type ? '保存修改' : '添加角色' }}</n-button>
        </n-form-item>
      </n-form>
    </n-modal>

  </div>
</template>

<script lang="ts" setup>
import {h, onMounted, reactive, ref} from 'vue';
import {useDialog, useMessage} from 'naive-ui';
import {BasicTable, TableAction} from '@/components/Table';
import {getRoleList, deleteRole, addRole, updateRole} from '@/api/authority/role';
import {getMenuTreeList} from '@/api/authority/menu';
import {columns} from './columns';
import {useRouter} from 'vue-router';

const router = useRouter();
const formRef: any = ref(null);
const message = useMessage();
const dialog = useDialog();
const actionRef = ref();

const treeData = ref([]);
const subLoading = ref(false);
const expandedKeys = ref([]);
const checkedKeys = ref([]);

const rules = {
  roleName: {
    required: true,
    message: '请输入角色名称',
    trigger: 'blur',
  },
  roleKey: {
    required: true,
    message: '请输入角色键',
    trigger: 'blur',
  },
  menuIds: {
    required: true,
    validator (rule, value: string) {
      if (!value || value.length < 1) {
        return new Error('请选择该角色绑定的菜单')
      }
      return true
    },
    trigger: 'blur',
  },
  sort: {
    required: true,
    validator (rule, value: string) {
      if (!value) {
        return new Error('请输入菜单序号')
      } else if (!/^\d*$/.test(value)) {
        return new Error('序号应该为整数')
      }
      return true
    },
    trigger: 'blur',
  },
};

const modelDetails = reactive({
  show: false,
  type: 0,
  title: ['添加角色信息', '修改角色信息'],
  formData: {
    id: 0,
    roleName: '',
    roleKey: '',
    sort: 1,
    menuIds: []
  }
})

const actionColumn = reactive({
  width: 120,
  title: '操作',
  key: 'action',
  fixed: 'right',
  render(row) {
    return h(TableAction, {
      style: 'text',
      actions: [
        {
          label: '编辑',
          onClick: () => {
            Object.assign(modelDetails.formData, row)
            modelDetails.type = 1
            modelDetails.show = true
          },
        },
        {
          label: '删除',
          onClick: () => {
            dialog.info({
              title: '提示',
              content: `您确定想删除该角色吗?`,
              positiveText: '确定',
              negativeText: '取消',
              onPositiveClick: () => {
                deleteRole(row.id)
                  .then(() => reloadTable())
                  .catch(() => dialog.destroyAll())
              },
              onNegativeClick: () => { },
            });
          },
          type: 'error'
        },
      ],
    });
  },
});

const loadDataTable = async () => {
  return {
    records: await getRoleList(true)
  };
};

function reloadTable() {
  actionRef.value.reload();
}

function onExpandedKeys(keys) {
  expandedKeys.value = keys;
}

function onCheckedKeys(keys) {
  modelDetails.formData.menuIds = keys
}

function formSubmit() {
  formRef.value.validate(async (errors: boolean) => {
    if (!errors) {
      subLoading.value = true;
      if (modelDetails.type === 0) {
        await addRole({
          roleKey: modelDetails.formData.roleKey,
          roleName: modelDetails.formData.roleName,
          sort: modelDetails.formData.sort,
          menuIds: modelDetails.formData.menuIds,
        }).catch(e => subLoading.value = false)
      } else if (modelDetails.type === 1) {
        await updateRole(modelDetails.formData.id, {
          roleKey: modelDetails.formData.roleKey,
          roleName: modelDetails.formData.roleName,
          sort: modelDetails.formData.sort,
          menuIds: modelDetails.formData.menuIds,
        }).catch(e => subLoading.value = false)
      }
      subLoading.value = false;
      modelDetails.show = false
      reloadTable()
    } else {
      message.error('请填写完整信息');
    }
  });
}

onMounted(async () => {
  treeData.value = await getMenuTreeList();
});
</script>

<style lang="less" scoped></style>
